﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using ModularAndPlugin.Core;
using ModularAndPlugin.Core.Composition;
using ModularAndPlugin.Core.Configuration;
using ModularAndPlugin.Core.Contracts;
using ModularAndPlugin.Core.IOC.ServiceLocation;
using ModularAndPlugin.WinApp.Contracts;
using SailHero.Soft.FrameWork.DAO.Contracts.Contracts;
namespace ModularAndPlugin.WinApp.Composition
{
    [Export(typeof(IModuleHandler))]
    public class ModuleHandler : IDisposable, IModuleHandler
    {

        // The importMany attribute allow us to import the classes that implement the same interface
        [ImportMany(typeof(IModule), AllowRecomposition = true)]
        // The ModuleList will be filled with the imported modules
        public List<Lazy<IModule, IModuleAttribute>> ModuleList
        { get; set; }

        [ImportMany(typeof(IMenu), AllowRecomposition = true)]
        // The MenuList will be filled with the imported Menus
        public List<IMenu> MenuList
        { get; set; }
        [ImportMany(typeof(IDomainRepositorie), AllowRecomposition = true)]
        public List<IDomainRepositorie> ImodelList
        { get; set; }
        [Import(typeof(IDAOInit))]
        public IDAOInit DAOInit
        { get; set; }

        [Import]
        public IDataModule DataModule { get; set; }

        [Import(typeof(IHost))]
        public IHost Host
        { get; set; }

        [ImportMany(typeof(Delegate))]
        public List<Lazy<Delegate, ICommandAttribute>> Commands
        { get; set; }

        // AggregateCatalog stores the MEF Catalogs
        AggregateCatalog catalog = new AggregateCatalog();

        public void InitializeModules()
        {
            // Create a new instance of ModuleList
            ModuleList = new List<Lazy<IModule, IModuleAttribute>>();
            // Create a new instance of MenuList
            MenuList = new List<IMenu>();

            Commands = new List<Lazy<Delegate, ICommandAttribute>>();


            var config = CompositionConfigurationSection.GetInstance();
            string basePath = AppDomain.CurrentDomain.BaseDirectory;
            if (config != null && config.Catalogs != null)
            {
                config.Catalogs
                    .Cast<CatalogConfigurationElement>()
                    .ForEach(c =>
                    {
                        if (!string.IsNullOrEmpty(c.Path))
                        {
                            string path = c.Path;
                            path = basePath + "/" + path;
                            if (System.IO.Directory.Exists(path))
                            {
                                catalog.Catalogs.Add(new DirectoryCatalog(path));
                            }
                        }
                    });
            }
            // Create a new catalog from the main app, to get the Host
            catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetCallingAssembly()));
            // Create a new catalog from the ModularWinApp.Core
            catalog.Catalogs.Add(new DirectoryCatalog(basePath));
            var composer = new Composer();
            composer.AddExportProvider(new CustomExportProvider());
            composer.AddCatalog(catalog);
            composer.Compose(this);
            composer.Compose(DataModule);
            //Func<bool> _cmd = (Func<bool>)FindDleg("NewClient");

            //_cmd.Invoke();

            InitDbContext();
        }


        public Delegate FindCmdByKey(string cmdKey)
        {
            Delegate taget = null;
            var dd = Commands.Select(itm => itm.Metadata.CmdKey);
            foreach (var l in Commands)
            {
                if (l.Metadata.CmdKey == cmdKey)
                {
                    taget = l.Value;
                    break;
                }
            }
            return taget;

        }



        //Verify if some module is imported
        public bool ContainsModule(string moduleName_)
        {
            bool ret = false;
            foreach (var l in ModuleList)
            {
                if (l.Metadata.ModuleName == moduleName_)
                {
                    ret = true;
                    break;
                }
            }
            return ret;
        }

        //return a module instance based on it's name
        public IModule GetModuleInstance(string moduleName_)
        {
            IModule instance = null;
            foreach (var l in ModuleList)
            {
                if (l.Metadata.ModuleName == moduleName_)
                {
                    instance = l.Value;
                    break;
                }
            }
            return instance;
        }

        public void Dispose()
        {
            catalog.Dispose();
            catalog = null;
            ModuleList.Clear();
            ModuleList = null;
        }

        public void InitDbContext()
        {

            DAOInit.InitDbContext_Win();

        }
    }
}
